package me.alide.common.utils;

/**
 * Created by wutairui on 2018/4/3.
 */

import okhttp3.*;
import okio.BufferedSink;
import okio.BufferedSource;
import okio.Okio;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.File;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
public class OkHttpUtils {

    private static final Logger logger = LoggerFactory.getLogger(OkHttpUtils.class);

    private OkHttpClient okHttpClient;
    private static OkHttpUtils okHttpUtil;

    public OkHttpUtils() {
        MyOkHttpRetryInterceptor myOkHttpRetryInterceptor = new MyOkHttpRetryInterceptor.Builder()
                .executionCount(3)
                .retryInterval(2000)
                .build();
        okHttpClient = new OkHttpClient.Builder()
                .retryOnConnectionFailure(true)
                .addInterceptor(myOkHttpRetryInterceptor)
//                .connectionPool(pool())
                .connectTimeout(5, TimeUnit.SECONDS)
                .readTimeout(5, TimeUnit.SECONDS)
                .writeTimeout(5, TimeUnit.SECONDS)
                .build();
    }


    public static OkHttpUtils getInstance() {
        if (null == okHttpUtil) {
            synchronized (OkHttpUtils.class) {
                if (null == okHttpUtil) {
                    okHttpUtil = new OkHttpUtils();
                }
            }
        }
        return okHttpUtil;
    }

    /**
     * get
     *
     * @param url     请求的url
     * @param queries 请求的参数，在浏览器？后面的数据，没有可以传null
     * @return
     */
    public String get(String url, Map<String, String> queries) throws IOException {
        String responseBody = "";
        StringBuffer sb = new StringBuffer(url);
        if (queries != null && queries.keySet().size() > 0) {
            boolean firstFlag = true;
            Iterator iterator = queries.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry entry = (Map.Entry<String, String>) iterator.next();
                if (firstFlag) {
                    sb.append("?" + entry.getKey() + "=" + entry.getValue());
                    firstFlag = false;
                } else {
                    sb.append("&" + entry.getKey() + "=" + entry.getValue());
                }
            }
        }
        Request request = new Request
                .Builder()
                .url(sb.toString())
                .build();
        Response response = null;
        response = okHttpClient.newCall(request).execute();
        int status = response.code();
        if (status == 200) {
            responseBody =  response.body().string();
            response.close();
        }
        return responseBody;
    }


    /**
     * post
     *
     * @param url    请求的url
     * @param params post form 提交的参数
     * @return
     */
    public String post(String url, Map<String, String> params) throws IOException {
        String responseBody = "";
        FormBody.Builder builder = new FormBody.Builder();
        //添加参数
        if (params != null && params.keySet().size() > 0) {
            for (String key : params.keySet()) {
                builder.add(key, params.get(key));
            }
        }
        Request request = new Request
                .Builder()
                .header("Content-Type", "application/x-www-form-urlencoded;charset=utf-8")
                .url(url)
                .post(builder.build())
                .build();
        Response response = null;
        response = okHttpClient.newCall(request).execute();
        int status = response.code();
        if (status == 200) {
            responseBody =  response.body().string();
            response.close();
        }
        return responseBody;
    }


    public String post(String url, String raw) throws IOException {
        String responseBody = "";
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json;charset=utf-8"), raw);
        Request request = new Request
                .Builder()
                .url(url)
                .post(requestBody)
                .build();
        Response response = null;
        response = okHttpClient.newCall(request).execute();
        int status = response.code();
        if (status == 200) {
            responseBody =  response.body().string();
            response.close();
        }
        return responseBody;
    }

    public File saveFile(String url, String filePath) throws IOException {
        OkHttpClient client = new OkHttpClient();
        logger.info("load file from: {}", url);
        Request request = new Request.Builder().url(url).build();
        Response response = client.newCall(request).execute();
        if (!response.isSuccessful()) {
            return null;
        }
        ResponseBody body = response.body();
        BufferedSource source = body.source();
        File file = new File(filePath);
        BufferedSink sink = Okio.buffer(Okio.sink(file));
        sink.writeAll(source);
        sink.flush();
        sink.close();
        response.close();
        return file;
    }


    /**
     * get
     *
     * @param url     请求的url
     * @param queries 请求的参数，在浏览器？后面的数据，没有可以传null
     * @return
     */
    public String get(String url, Map<String, String> queries, Map<String, String> headers) throws IOException {
        String responseBody = "";
        StringBuffer sb = new StringBuffer(url);
        if (queries != null && queries.keySet().size() > 0) {
            boolean firstFlag = true;
            Iterator iterator = queries.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry entry = (Map.Entry<String, String>) iterator.next();
                if (firstFlag) {
                    sb.append("?" + entry.getKey() + "=" + entry.getValue());
                    firstFlag = false;
                } else {
                    sb.append("&" + entry.getKey() + "=" + entry.getValue());
                }
            }
        }
        Request.Builder builder = new Request.Builder();
        builder.url(sb.toString());
        Request request;
        if(headers != null && headers.keySet().size() > 0) {
            for(String key : headers.keySet()) {
                builder.addHeader(key, headers.get(key));
            }
        }
        request =  builder.build();
        Response response = okHttpClient.newCall(request).execute();
        int status = response.code();
        if (status == 200) {
            responseBody =  response.body().string();
            response.close();
        }
        return responseBody;
    }


    /**
     * post
     *
     * @param url    请求的url
     * @param params post form 提交的参数
     * @return
     */
    public String post(String url, Map<String, String> params, Map<String, String> headers) throws IOException {
        String responseBody = "";
        FormBody.Builder builder = new FormBody.Builder();
        //添加参数
        if (params != null && params.keySet().size() > 0) {
            for (String key : params.keySet()) {
                builder.add(key, params.get(key));
            }
        }
        Request.Builder requestBuilder = new Request.Builder();
        requestBuilder.addHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
        if(headers != null && headers.keySet().size() > 0) {
            for(String key : headers.keySet()) {
                requestBuilder.addHeader(key, headers.get(key));
            }
        }
        Request request = requestBuilder
                .url(url)
                .post(builder.build())
                .build();
        Response response;
        response = okHttpClient.newCall(request).execute();
        int status = response.code();
        if (status == 200) {
            responseBody =  response.body().string();
            response.close();
        }
        return responseBody;
    }


    public String post(String url, String raw, Map<String, String> headers) throws IOException {
        String responseBody = "";
        RequestBody requestBody = RequestBody.create(MediaType.parse("application/json;charset=utf-8"), raw);
        Request.Builder requestBuilder = new Request.Builder();
        requestBuilder.addHeader("Content-Type", "application/x-www-form-urlencoded;charset=utf-8");
        if(headers != null && headers.keySet().size() > 0) {
            for(String key : headers.keySet()) {
                requestBuilder.addHeader(key, headers.get(key));
            }
        }
        Request request = requestBuilder
                .url(url)
                .post(requestBody)
                .build();
        Response response;
        response = okHttpClient.newCall(request).execute();
        int status = response.code();
        if (status == 200) {
            responseBody =  response.body().string();
            response.close();
        }
        return responseBody;
    }

    /**
     * post 上传文件
     *
     * @param url
     * @param params
     * @param fileType
     * @return
     */
    public String postFile(String url, Map<String, Object> params, String fileType) throws IOException {
        String responseBody = "";
        MultipartBody.Builder builder = new MultipartBody.Builder();
        //添加参数
        if (params != null && params.keySet().size() > 0) {
            for (String key : params.keySet()) {
                if (params.get(key) instanceof File) {
                    File file = (File) params.get(key);
                    builder.addFormDataPart(key, file.getName(), RequestBody.create(MediaType.parse(fileType), file));
                    continue;
                }
                builder.addFormDataPart(key, params.get(key).toString());
            }
        }
        Request request = new Request
                .Builder()
                .url(url)
                .post(builder.build())
                .build();
        Response response = null;
        response = okHttpClient.newCall(request).execute();
        int status = response.code();
        if (status == 200) {
            responseBody =  response.body().string();
            response.close();
        }
        return responseBody;
    }


    public X509TrustManager x509TrustManager() {
        return new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

            }

            @Override
            public void checkServerTrusted(X509Certificate[] x509Certificates, String s) throws CertificateException {

            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];
            }
        };
    }

    public SSLSocketFactory sslSocketFactory() {
        try {
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[]{x509TrustManager()}, new SecureRandom());
            return  sslContext.getSocketFactory();
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (KeyManagementException e) {
            e.printStackTrace();
        }
        return  null;
    }

    public ConnectionPool pool () {
        return  new ConnectionPool(200, 5, TimeUnit.MINUTES);
    }

    public OkHttpClient getOkHttpClient() {
        return okHttpClient;
    }

    public void setOkHttpClient(OkHttpClient okHttpClient) {
        this.okHttpClient = okHttpClient;
    }
}